#define __AT_AIRKISS_C_
#include "at_airkiss.h"
#include "WifiConfig_hal_sys_api.h"

airkiss_context_t ac;
airkiss_config_t acfg = {
    (airkiss_memset_fn)&memset,
    (airkiss_memcpy_fn)&memcpy,
    (airkiss_memcmp_fn)&memcmp,
    (airkiss_printf_fn)NULL
};
airkiss_result_t airkresult;
static QueueHandle_t xQueue1 = NULL;

uint8_t channellist[15];
const uint8_t addr2[6] = {0x54,0x48,0xF6,0xB2,0x8B,0xB6};
const uint8_t addr3[6] = {0xE2,0xB6,0x0F,0xC4,0x49,0x09};

static int _airkiss_filter(const void *f, int len)
{
    int ret = 0;
    unsigned char *da, *p;
    int i;

    p = (unsigned char *)f;
    if ((len < 25) || (p[0] != 0x08))
        return 1;

    da = p + 4;

    for (i = 0; i < 6; i++)
    {
        if (da[i] != 0xFF)
        {
            ret = 1;
            break;
        }
    }

    return ret;
}

typedef struct queuedat
{
	uint8_t *pdat;
	int len;
}QUEUEDAT;

static void sniffer_cb_ex(void *env, uint8_t *pkt, int len)
{
    if (_airkiss_filter(pkt, len))
	{
		// axk_at_printf("failt len is %d\r\n",len);
		return;
	}
	// axk_at_printf("success len is %d\r\n",len);
	QUEUEDAT dat;
	dat.pdat = pkt;
	dat.len = len;

    xQueueSend(xQueue1,&dat,0);
}

typedef struct
{
    char n;
    unsigned char tm;
    unsigned short cnt;
} akchn_t;

static void akchn_init(akchn_t *chn, int n)
{
    int i;

    for (i = 0; i < n; i++)
    {
        chn[i].n = i + 1;
        chn[i].cnt = 0;
        chn[i].tm = 20;
    }
}

static int ak_recv(airkiss_context_t *ac, int ms, int *rcnt)
{
	BaseType_t xResult;
    int status = AIRKISS_STATUS_CONTINUE;
	// char ucQueueMsgValue;
	QUEUEDAT ucQueueMsgValue;
    uint64_t st, max;
    int len = 0;

    st =  bl_os_get_time_ms();

    while (1)
    {
        xResult = xQueueReceive(xQueue1,                   /* 消息队列句柄 */
                                (void *)&ucQueueMsgValue,  /* 存储接收到的数据到变量ucQueueMsgValue中 */
                                10);/* 设置阻塞时间 */		
		if(xResult == pdPASS)
		{
            status = airkiss_recv(ac, ucQueueMsgValue.pdat, ucQueueMsgValue.len);

            if (status != AIRKISS_STATUS_CONTINUE)
                break;

            if (rcnt && (ucQueueMsgValue.len != len))
            {
                (*rcnt)++;
                len = ucQueueMsgValue.len;
                if (ms < 180)
                    ms += 12;
            }			
		}
		else
		{
            if ((ms > 30) && rcnt)
                ms -= 2;
		}

        max = ms;
        if ((bl_os_get_time_ms() - st) > max)
            break;
    }

    return status;
}

static int ak_recv_chn(airkiss_context_t *ac, akchn_t *chn)
{
    int status;
    int t;
    int rcnt = 0;

	wifi_mgmr_channel_set(chn->n, 1);
    airkiss_change_channel(ac);

    status = ak_recv(ac, chn->tm, &rcnt);

    if (status == AIRKISS_STATUS_CHANNEL_LOCKED)
    {
        // axk_at_printf("airkiss locked chn %d\n", chn->n);
		//30秒内要把数据识别出来
        status = ak_recv(ac, 1000 * 30, NULL);
    }

    chn->cnt += rcnt;
    if (chn->cnt > 5)
        chn->cnt -= 3;
    t = chn->cnt * chn->cnt * chn->cnt;

    if (t)
    {
        if (t > 170)
            t = 170;
        chn->tm = 30 + t;
        // axk_at_printf("tm(%d) cnt(%d) on chn %d\n", chn->tm, chn->cnt, chn->n);
    }

    return status;
}

static void udp_data_packet_airkiss(uint8_t *buff,uint8_t random)
{
    uint8_t mac[6];
    uint32_t ip_u32, gw_u32, netmask_u32;

    /* mApSsid.length + mApPassword.length + 9 */
    buff[0] = random;

    /* bssid */
    wifi_mgmr_sta_mac_get(mac);
    memcpy(buff + 1, mac, sizeof mac);

    // /* local ip */
    // wifi_mgmr_sta_ip_get(&ip_u32, &gw_u32, &netmask_u32);
    // memcpy(buff + 7, &ip_u32, sizeof ip_u32);
}

static void airkiss_send_notification(uint8_t random)
{
	int count = 0;
	while(WifiConfigGetWifiStatus() != AT_WIFI_STATE_CONNECTED_GOT_IP)
	{
		count ++;
		if(count > 2000)
		{
			return;
		}
		vTaskDelay(10);
	}
    int sock = -1;
    int udpbufsize = 2;
    uint8_t datbuf[7] = {0};
    struct sockaddr_in UDPBCAddr, UDPBCServerAddr;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        // axk_at_printf("notify socket open error\n");
        goto _exit;
    }

    UDPBCAddr.sin_family = AF_INET;
    UDPBCAddr.sin_port = htons(10000);
    UDPBCAddr.sin_addr.s_addr = htonl(0xffffffff);
	memset(&(UDPBCAddr.sin_zero), 0, sizeof(UDPBCAddr.sin_zero));

    UDPBCServerAddr.sin_family = AF_INET;
    UDPBCServerAddr.sin_port = htons(10000);
    UDPBCServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    memset(&(UDPBCServerAddr.sin_zero), 0, sizeof(UDPBCServerAddr.sin_zero));

    if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &udpbufsize, sizeof(int)) != 0)
    {
        // axk_at_printf("notify socket set error\n");
        goto _exit;
    }

    if (bind(sock, (struct sockaddr *)&UDPBCServerAddr, sizeof(UDPBCServerAddr)) != 0)
    {
        // axk_at_printf("notify socket bind error\n");
        goto _exit;
    }

    udp_data_packet_airkiss(datbuf,random);
    for (int i = 0; i <= 20; i++)
    {
        // int ret = sendto(sock, (char *)&random, 1, 0, (struct sockaddr *)&UDPBCAddr, sizeof(UDPBCAddr));
        int ret = sendto(sock, (char *)&datbuf, sizeof(datbuf), 0, (struct sockaddr *)&UDPBCAddr, sizeof(UDPBCAddr));
        if(ret == 0)
        {
            break;
            // int ret = sendto(sock, (char *)&mac, 6, 0, (struct sockaddr *)&UDPBCAddr, sizeof(UDPBCAddr));
            // break;
            // axk_at_printf("notify socket send error\n");
            // i --;
        }
        vTaskDelay(10);
    }

_exit:
    if (sock >= 0)
    {
        int ret = closesocket(sock);
        if(ret != 0)
        {
            // axk_at_printf("notify socket close error\n");
        }
    }
}

static unsigned char mrandom;

void AirKissProcessThread(void *msg)
{
	akchn_t chns[13];
	int round = 120;

	airkiss_init(&ac, &acfg);

	xQueue1 = xQueueCreate(1, sizeof(QUEUEDAT));

    extern int axk_hal_wifi_mode_set(uint8_t mode, uint8_t auto_conn);
    axk_hal_wifi_mode_set(0, 0);
    wifi_mgmr_sniffer_disable();
    wifi_mgmr_sniffer_register(NULL, sniffer_cb_ex);
    wifi_mgmr_sniffer_enable();
	// wifi_mgmr_channel_set(6, 1);

	akchn_init(chns, sizeof(chns) / sizeof(chns[0]));
	// axk_at_printf("airkiss start time is %lld\r\n",bl_os_get_time_ms());

	while(round-- > 0)
	{
		// axk_at_printf("round len is %d\r\n", round);
        for (int r = 0; r < sizeof(chns) / sizeof(chns[0]); r++)
        {
            if (ak_recv_chn(&ac, &chns[r]) == AIRKISS_STATUS_COMPLETE)
            {
                airkiss_result_t res;

				wifi_mgmr_sniffer_disable();

                airkiss_get_result(&ac, &res);

                // axk_at_printf("pwd %s ssid %s\r\n", res.pwd, res.ssid);
                axk_at_wifi_sc_get_info_export(res.ssid,res.pwd);
                mrandom = res.random;
				// axk_at_printf("airkiss time is:%d\r\n",(bl_os_get_time_ms() - timervalue));
				if (ak_wifi_connetct(res.ssid, res.pwd) == 0)
                {
                    // mrandom = res.random;
                    // axk_at_printf("wifi connetct success\r\n");
                    // axk_at_wifi_sc_connect_ap_success_export(res.ssid,res.pwd);
					// axk_at_printf("airkiss end time is %lld\r\n",bl_os_get_time_ms());
					// axk_at_printf("sta time is:%d\r\n",(bl_os_get_time_ms() - timervalue));
                }

				return;
            }
        }		
	}
}

static at_hal_threadParams_t thread_params;

int axk_airkiss()
{
    thread_params.thread_func = AirKissProcessThread;
    thread_params.thread_name = "AirKissProcessThread";
    thread_params.stack_size = 4096;
    thread_params.priority = 10;
    thread_params.user_arg = NULL;
    int ret = axk_hal_thread_create(&thread_params);

    if (AT_ERR_SUCCESS != ret)
    {
        // at_log("axk_hal_thread_create(axk_at_task) failed!\r\n");
        return AT_ERR_FAILURE;
    }

	return 0;
}

static void airkiss_wifi_event(int code, int value)
{
    switch (code)
    {
        case CODE_WIFI_ON_DISCONNECT: {
            printf("[SC] disconn, value:%d\r\n", value);
        }
        break;
        case CODE_WIFI_ON_CONNECTED: {

        }
        break;
        case CODE_WIFI_ON_GOT_IP: {
            wifi_mgmr_sta_connect_ind_stat_info_t stat;

            wifi_mgmr_sta_connect_ind_stat_get(&stat);
            axk_at_wifi_sc_connect_ap_success_export(stat.ssid, stat.passphr);
            airkiss_send_notification(mrandom);
        }
        break;
        default: {
            printf("[SC] Unknown code %u\r\n", code);
        }
    }
}

int wifi_airkiss_v1_start(void)
{
    wifi_event_register(airkiss_wifi_event);

    return axk_airkiss();
}

int wifi_airkiss_v1_stop(void)
{
    wifi_event_register(NULL);

    wifi_mgmr_sniffer_disable();
    wifi_mgmr_sniffer_unregister(NULL);

    axk_hal_thread_destroy(&thread_params);

    return 0;
}
